package agent.monitors;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.snmp4j.smi.OctetString;

public class TorrentInterface implements TorrentMonitor{
	private static final String beginList = ", ,\"torrents\": [, , [";
	private static final String endList = "]], ,\"torrentc\":";
	private static final String listSpliter = "\\],, \\[";
	
	private String base_url = "http://localhost:8080/gui/";
	private LinkedList<String> webContent;
	private CookieManager cookie;
	private String token;
	
	//SETTINGS BRANCH
	private String maxDl;
	private String maxUl;
	private String pex;
	private String port;
	private String maxActive;
	
	//FILES BRANCH
	ArrayList<TorrentFile> files;
	
	public TorrentInterface(String url)
	{
		//Setting Cookies
		cookie = new CookieManager();
		cookie.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
		CookieHandler.setDefault(cookie);
		
		base_url = url+"/gui/";
		webContent = new LinkedList<String>();
		
		this.readUrl("token.html");
		token = this.parseToken();
		
		this.updateValues();
	}
	
	public void readUrl(String path) {
		try {
			// Sets the authenticator that will be used by the networking code
		    // when a proxy or an HTTP server asks for authentication.
			Authenticator.setDefault(new CustomAuthenticator());
			
			URL url = new URL(base_url+path);
			webContent.clear();
			
			// read text returned by server
		    BufferedReader output = new BufferedReader(new InputStreamReader(url.openStream()));
		    
		    String line;
		    while ((line = output.readLine()) != null) {
		    	webContent.add(line);
		    }
		    output.close();
		}
		catch (MalformedURLException e) {
			System.out.println("Malformed URL: " + e.getMessage());
		}
		catch (IOException e) {
			System.out.println("I/O Error: " + e.getMessage());
		}

	}
	
		
	private String parseToken()
	{
		String t = webContent.getFirst();
		String token = t.replace("<", ">").split(">")[4];
	 	return token;
	}
	
	private boolean getSettings()
	{
		boolean changed = false;
		String attr;
		String value = null;
		for(String line:webContent)
		{
			if(line.contains("\""))
			{
				attr = line.split("\"")[1];
				if(attr.contentEquals("pex")){
					value = line.split("\"")[3];
					if((this.pex != null && !this.pex.equals(value)) || (this.pex == null && value != null)){
						this.pex = value;
						changed = true;
					}
				}
				else
				if(attr.contentEquals("max_dl_rate")){
					value = line.split("\"")[3];
					if((this.maxDl != null && !this.maxDl.equals(value)) || (this.maxDl == null && value != null)){
						this.maxDl = value;
						changed = true;
					}
				}
				else
				if(attr.contentEquals("max_ul_rate")){
					value = line.split("\"")[3];
					if((this.maxUl != null && !this.maxUl.equals(value)) || (this.maxUl == null && value != null)){
						this.maxUl = value;
						changed = true;
					}
				}
				else
				if(attr.contentEquals("bind_port")){
					value = line.split("\"")[3];
					if((this.port != null && !this.port.equals(value)) || (this.port == null && value != null)){
						this.port = value;
						changed = true;
					}
				}
				else
				if(attr.contentEquals("max_active_torrent")){
					value = line.split("\"")[3];
					if((this.maxActive != null && !this.maxActive.equals(value)) || (this.maxActive == null && value != null)){
						this.maxActive = value;
						changed = true;
					}
				}
			}
		}
		return changed;
	}
	
	public boolean getTorrents()
	{
		boolean changed = false;
		
		ArrayList<TorrentFile> newFiles = new ArrayList<TorrentFile>();
		
		if(this.webContent.size() > 8)
		{
			String webContent = this.webContent.toString();
			String results = webContent.substring(webContent.indexOf(beginList)+beginList.length(), webContent.indexOf(endList));
			
			
			
			String[] filesString = results.split(listSpliter);
			String[] filteredFileData = new String[12];
			String[] rawFileData; 
			
			for (String string : filesString) {
				rawFileData = string.split(",");
				
				filteredFileData[0]  = rawFileData[0].substring(1, rawFileData[0].lastIndexOf('"')); //colHash
				filteredFileData[1]  = rawFileData[1]; //colStatus
				filteredFileData[2]  = rawFileData[2].substring(1, rawFileData[2].lastIndexOf('"')); //colName
				filteredFileData[3]  = rawFileData[3]; //colSize
				filteredFileData[4]  = rawFileData[4]; //colPercent
				filteredFileData[5]  = rawFileData[5]; //colDownloaded
				filteredFileData[6]  = rawFileData[6]; //colUploaded
				filteredFileData[7]  = rawFileData[8]; //colUploadSpeed
				filteredFileData[8]  = rawFileData[9]; //colDownloadSpeed
				filteredFileData[9]  = rawFileData[10]; //colEta
				filteredFileData[10] = rawFileData[12]; //colPeersConnected
				filteredFileData[11] = rawFileData[14]; //colSeedsConnected
				
				newFiles.add(new TorrentFile(filteredFileData));
			}
		}
		
		if(this.files == null){
			changed =  newFiles != null;
		}
		else if(this.files.size() != newFiles.size()){
			changed = true;
		}
		else{
			for (TorrentFile torrentFile : this.files) {
				for (TorrentFile newTorrentFile : newFiles) {
					if (torrentFile.equals(newTorrentFile)){
						changed = true;
					}
				}
			}
		}
		
		if(changed){
			this.files = newFiles;
			return true;
		}
		else {
			return false;
		}
		
	}

	
	public boolean updateValues() {
		boolean settingsChanged = false;
		boolean filesChanged = false;
//		this.readUrl("token.html");
//		token = this.parseToken();
		this.readUrl("?token="+token+"&action=getsettings");
		settingsChanged = this.getSettings();
		this.readUrl("?token="+token+"&list=1");
		filesChanged = this.getTorrents();
		
		return (settingsChanged || filesChanged);
	}

	@Override
	public String getMaxUl() {
		return this.maxUl;
	}

	@Override
	public String getMaxDl() {
		return this.maxDl;
	}

	@Override
	public String getMaxActive() {
		return this.maxActive;
	}

	@Override
	public String getPex() {
		return this.pex;
	}

	@Override
	public String getPort() {
		return this.port;
	}

	@Override
	public List<TorrentFile> getFileEntry() {
		return this.files;
	}

	public String setSettings(String name, String value)
	{
		String base = "&action=setsetting&s=";
		if(name == "maxDl")
			return base+"max_dl_rate&v="+value;
		if(name == "maxUl")
			return base+"max_ul_rate&v="+value;
		if(name == "maxActive")
			return base+"max_active_torrent&v="+value;
		if(name == "pex")
			return base+"pex&v="+value;
		if(name == "port")
			return base+"bind_port&v="+value;
		System.out.println("Error! Cannot find name to set");
		System.exit(1);
		return null;
	}
	
	@Override
	public void setMaxUl(OctetString newValue) {
		this.maxUl = newValue.toString();
		String setUrl = this.setSettings("maxUl", newValue.toString());
		this.readUrl("?token="+token+setUrl);
	}

	@Override
	public void setMaxDl(OctetString newValue) {
		this.maxDl = newValue.toString();
		String setUrl = this.setSettings("maxDl", newValue.toString());
		this.readUrl("?token="+token+setUrl);
	}

	@Override
	public void setMaxActive(OctetString newValue) {
		this.maxActive = newValue.toString();
		String setUrl = this.setSettings("maxActive", newValue.toString());
		this.readUrl("?token="+token+setUrl);
	}

	@Override
	public void setPex(OctetString newValue) {
		this.pex = newValue.toString();
		String setUrl = this.setSettings("pex", newValue.toString());
		this.readUrl("?token="+token+setUrl);
	}

	@Override
	public void setPort(OctetString newValue) {
		this.port = newValue.toString();
		String setUrl = this.setSettings("port", newValue.toString());
		this.readUrl("?token="+token+setUrl);
	}
}
